
#include <mpi.h>
#include <malloc.h>

#include "mpi-utiles.h"
#include "log.h"


// Acumulador de tiempo ocioso
double tiempoEspera = 0;

/*
 * Implementación de funcion definida en cabecera
 */
struct DATOS_RECIBIDOS recibirDatos(int origen, int tag) {

    LOGGER("Nos bloqueamos a la espera de desde %d, con tag %d", origen, tag);
    
    // Guardamos el memento inicial
    double inicio = MPI_Wtime();
    
    // Esperamos que llegue un mensaje
    MPI_Status mensaje;
    MPI_Probe(origen, tag, MPI_COMM_WORLD, &mensaje);
    
    LOGGER("Llegaron datos, obtenemos el tamaño en bytes");
    
    // Obtenemos el tamaño del mismo y creamos un buffer para recibirlo
    int tamanio;
    MPI_Get_count(&mensaje, MPI_BYTE, &tamanio);
    char *buffer = malloc(sizeof(char) * tamanio);
    
    // Recibimos el mensaje
    LOGGER("Recibimos %d bytes", tamanio);
    MPI_Recv(buffer, tamanio, MPI_BYTE, origen, tag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
    LOGGER("Datos recibidos");
    
    // Guardamos el memento final y acumulamos el tiempo
    double final = MPI_Wtime();
    tiempoEspera += final-inicio;
    
    // Creamos el objeto a retornar y lo retornamos
    struct DATOS_RECIBIDOS recepcion;
    recepcion.datos = buffer;
    recepcion.tamanio = tamanio;
    
    return recepcion;
    
}


/*
 * Implementación de funcion definida en cabecera
 */
void enviarDatos(int destino, int tag, char *datos, int tam) {
    
    LOGGER("Enviamos datos al nodo %d, con el tag %d", destino, tag);
    
    // Guardamos el memento inicial
    double inicio = MPI_Wtime();
    
    MPI_Send(datos, tam, MPI_BYTE, destino, tag, MPI_COMM_WORLD);
    
    // Guardamos el memento final y acumulamos el tiempo
    double final = MPI_Wtime();
    tiempoEspera += final-inicio;
    
    LOGGER("Fin del envío");
    
}


/*
 * Implementación de funcion definida en cabecera
 */
int obtenerCantidadDeNodosDeTrabajo() {
    
    // Obtenemos la cantidad total de nodos
    int cantidadNodos;
    MPI_Comm_size(MPI_COMM_WORLD, &cantidadNodos);
    
    // La cantidad de nodos de trabajo es la cantidad de nodos menos 1 (el coordinador)
    return cantidadNodos - 1;
    
}


/*
 * Implementación de funcion definida en cabecera
 */
double obtenerTiempoEspera() {
    return tiempoEspera;
}